/*!
 * \file set_relation_test_moldyn.cc
 *
 * \brief Set and Relation tests from operations performed by the Python
 * implementation of the moldyn_full spec file and applying transformations up
 * to and including the sparse loop optimization.
 *
 * \date Started: 12/14/2010
 * \date Last Modified: 12/14/2010
 * \authors Alan LaMielle
 */

#include <iegenlib/iegenlib.h>

#include <gtest/gtest.h>

using iegenlib::Set;
using iegenlib::Relation;

TEST(MoldynRealTest,set_union_tests){
   //These tests were taken from a full run of the Python version of IEGen using
   //the moldyn_full computation applying transformations up to sparse loop
   vector<string> union_in1s,union_in2s,expected_results;

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and tstep0>=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,2,ii0,0]: n_tstep>=1+tstep0 and tstep0>=0 and ii0>=0 and n_inter>=1+ii0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and n_inter>=1+i0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and n_inter>=1+i0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0>=0 and n_inter>=1+i0} union {[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,2,ii0,0]: n_tstep>=1+tstep0 and tstep0>=0 and ii0>=0 and n_inter>=1+ii0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and n_inter>=1+i0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and n_inter>=1+i0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0>=0 and n_inter>=1+i0} union {[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,2,ii0,0]: n_tstep>=1+tstep0 and tstep0>=0 and ii0>=0 and n_inter>=1+ii0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and n_inter>=1+i0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and n_inter>=1+i0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0>=0 and n_inter>=1+i0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,2,ii0,0]: n_tstep>=1+tstep0 and tstep0>=0 and ii0>=0 and n_inter>=1+ii0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and n_inter>=1+i0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and n_inter>=1+i0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0>=0 and n_inter>=1+i0} union {[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,2,ii0,0]: n_tstep>=1+tstep0 and tstep0>=0 and ii0>=0 and n_inter>=1+ii0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and n_inter>=1+i0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and n_inter>=1+i0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0>=0 and n_inter>=1+i0} union {[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,2,ii0,0]: n_tstep>=1+tstep0 and tstep0>=0 and ii0>=0 and n_inter>=1+ii0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and n_inter>=1+i0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and n_inter>=1+i0 and i0>=0 and tstep0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0>=0 and n_inter>=1+i0} union {[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,2,i0,x0]: i0>=0 and n_moles>=1+i0 and n_tstep>=1+s0 and t=theta(2,i0) and s0>=0 and 0=x0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and x0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,2,i0,x0]: i0>=0 and n_moles>=1+i0 and n_tstep>=1+s0 and t=theta(2,i0) and s0>=0 and 0=x0} union {[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,2,i0,x0]: i0>=0 and n_moles>=1+i0 and n_tstep>=1+s0 and t=theta(2,i0) and s0>=0 and 0=x0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,2,i0,x0]: i0>=0 and n_moles>=1+i0 and n_tstep>=1+s0 and t=theta(2,i0) and s0>=0 and 0=x0} union {[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,2,i0,x0]: i0>=0 and n_moles>=1+i0 and n_tstep>=1+s0 and t=theta(2,i0) and s0>=0 and 0=x0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,2,i0,x0]: i0>=0 and n_moles>=1+i0 and n_tstep>=1+s0 and t=theta(2,i0) and s0>=0 and 0=x0} union {[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,2,i0,x0]: i0>=0 and n_moles>=1+i0 and n_tstep>=1+s0 and t=theta(2,i0) and s0>=0 and 0=x0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0} union {[0,s0,1,t,2,i0,x0]: i0>=0 and n_moles>=1+i0 and n_tstep>=1+s0 and t=theta(2,i0) and s0>=0 and 0=x0} union {[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)} union {[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");

   //Make sure there are equal numbers of inputs
   ASSERT_EQ(union_in1s.size(),union_in2s.size());
   ASSERT_EQ(union_in2s.size(),expected_results.size());

   for(int i=0; i<union_in1s.size(); i++) {
      Set union_in1(union_in1s[i]);
      Set union_in2(union_in2s[i]);
      Set result(union_in1.Union(union_in2));
      Set expected_result(expected_results[i]);

      ASSERT_EQ(result,expected_result) <<
         union_in1.get_isl() << endl << ".Union(" << union_in2.get_isl() <<
         ") !=" << expected_result.get_isl();
   }
}

TEST(MoldynRealTest,relation_union_tests){
   //These tests were taken from a full run of the Python version of IEGen using
   //the moldyn_full computation applying transformations up to sparse loop
   vector<string> union_in1s,union_in2s,expected_results;

   union_in1s.push_back("{[0,s,2,ii,x]->[0,s,2,ii,x]}");
   union_in2s.push_back("{[0,s,3,i,x]->[0,s,3,j,x]: j=sigma(i)}");
   expected_results.push_back("{[0,s,2,ii,x]->[0,s,2,ii,x]} union {[0,s,3,i,x]->[0,s,3,ii,x]: ii=sigma(i)}");

   union_in1s.push_back("{[0,s,1,i,0]->[0,s,1,j,0]: j=sigma(i)}");
   union_in2s.push_back("{[0,s,2,ii,0]->[0,s,2,i,0]} union {[0,s,3,ii,0]->[0,s,3,ii,0]: ii=sigma(i)}");
   expected_results.push_back("{[0,s,1,i,0]->[0,s,1,j,0]: j=sigma(i)} union {[0,s,2,ii,0]->[0,s,2,i,0]} union {[0,s,3,ii,0]->[0,s,3,ii,0]: ii=sigma(i)}");

   union_in1s.push_back("{[0,s,0,i,0]->[0,s,0,i,0]: i=0}");
   union_in2s.push_back("{[0,s,2,i,0]->[0,s,2,i,0]} union {[0,s,3,i,0]->[0,s,3,j,0]: j=sigma(i)} union {[0,s,1,i,0]->[0,s,1,j,0]: j=sigma(i)}");
   expected_results.push_back("{[0,s,2,i,0]->[0,s,2,i,0]} union {[0,s,3,i,0]->[0,s,3,j,0]: j=sigma(i)} union {[0,s,1,i,0]->[0,s,1,j,0]: j=sigma(i)} union {[0,s,0,i,0]->[0,s,0,i,0]: i=0}");

   union_in1s.push_back("{[0,s,2,j,x]->[0,s,2,e,x]: e=delta(j)}");
   union_in2s.push_back("{[0,s,3,i,x]->[0,s,3,i,x]}");
   expected_results.push_back("{[0,s,2,j,x]->[0,s,2,e,x]: e=delta(j)} union {[0,s,3,j,x]->[0,s,3,j,x]}");

   union_in1s.push_back("{[0,s,1,i,0]->[0,s,1,i,0]}");
   union_in2s.push_back("{[0,s,2,j,0]->[0,s,2,e,0]: e=delta(j)} union {[0,s,3,j,0]->[0,s,3,j,0]}");
   expected_results.push_back("{[0,s,2,i,0]->[0,s,2,i0,0]: i0=delta(i)} union {[0,s,1,i,0]->[0,s,1,i,0]} union {[0,s,3,i,0]->[0,s,3,i,0]}");

   union_in1s.push_back("{[0,s,0,i,0]->[0,s,0,i,0]: i=0}");
   union_in2s.push_back("{[0,s,2,i,0]->[0,s,2,i0,0]: i0=delta(i)} union {[0,s,1,i,0]->[0,s,1,i,0]} union {[0,s,3,i,0]->[0,s,3,i,0]}");
   expected_results.push_back("{[0,s,2,k,0]->[0,s,2,j,0]: j=delta(k)} union {[0,s,1,i,0]->[0,s,1,i,0]} union {[0,s,3,i,0]->[0,s,3,i,0]} union {[0,s,0,i,0]->[0,s,0,i,0]: i=0}");

   union_in1s.push_back("{[x,s,y,i,z]->[y,i]: y=1}");
   union_in2s.push_back("{[x,s,y,i,z]->[y,i]: y=2}");
   expected_results.push_back("{[x,s,y,i,z]->[y,i]: y=2} union {[x,s,y,i,z]->[y,i]: y=1}");

   union_in1s.push_back("{[x,s,y,i,z]->[y,i]: y=2} union {[x,s,y,i,z]->[y,i]: y=1}");
   union_in2s.push_back("{[x,s,y,i,z]->[y,i]: y=3}");
   expected_results.push_back("{[x,s,y,i,z]->[y,i]: y=3} union {[x,s,y,i,z]->[y,i]: y=2} union {[x,s,y,i,z]->[y,i]: y=1}");

   union_in1s.push_back("[n_inter,n_moles,nt]->{[1,i]->[2,k]: n_moles>=1+i and n_inter>=1+k and i=sigma_inter1_delta_inv(k) and k>=0 and i>=0}");
   union_in2s.push_back("[n_inter,n_moles,nt]->{[1,i]->[2,k]: n_moles>=1+i and n_inter>=1+k and k>=0 and i>=0 and i=sigma_inter2_delta_inv(k)}");
   expected_results.push_back("[n_inter,n_moles,nt]->{[1,i]->[2,k]: n_moles>=1+i and i>=0 and k>=0 and n_inter>=1+k and i=sigma_inter2_delta_inv(k)} union {[1,i]->[2,k]: n_moles>=1+i and i>=0 and i=sigma_inter1_delta_inv(k) and k>=0 and n_inter>=1+k}");

   union_in1s.push_back("[n_inter,n_moles,nt]->{[2,k]->[3,i]: n_moles>=1+i and i>=0 and k>=0 and n_inter>=1+k and i=sigma_inter1_delta_inv(k)}");
   union_in2s.push_back("[n_inter,n_moles,nt]->{[2,k]->[3,i]: n_moles>=1+i and i>=0 and k>=0 and n_inter>=1+k and i=sigma_inter2_delta_inv(k)}");
   expected_results.push_back("[n_inter,n_moles,nt]->{[2,k]->[3,i]: n_moles>=1+i and i>=0 and k>=0 and n_inter>=1+k and i=sigma_inter1_delta_inv(k)} union {[2,k]->[3,i]: n_moles>=1+i and i>=0 and k>=0 and n_inter>=1+k and i=sigma_inter2_delta_inv(k)}");

   union_in1s.push_back("[nt]->{[0,s,1,i,x]->[0,s,1,t,0,i,x]: t=theta(0,i)}");
   union_in2s.push_back("[nt]->{[0,s,2,i,x]->[0,s,1,t,1,i,x]: t=theta(1,i)}");
   expected_results.push_back("[nt]->{[0,s,1,i,x]->[0,s,1,t,0,i,x]: t=theta(0,i)} union {[0,s,2,i,x]->[0,s,1,t,1,i,x]: t=theta(1,i)}");

   union_in1s.push_back("[nt]->{[0,s,1,i,x]->[0,s,1,t,0,i,x]: t=theta(0,i)} union {[0,s,2,i,x]->[0,s,1,t,1,i,x]: t=theta(1,i)}");
   union_in2s.push_back("[nt]->{[0,s,3,i,x]->[0,s,1,t,2,i,x]: t=theta(2,i)}");
   expected_results.push_back("[nt]->{[0,s,1,i,x]->[0,s,1,t,0,i,x]: t=theta(0,i)} union {[0,s,2,i,x]->[0,s,1,t,1,i,x]: t=theta(1,i)} union {[0,s,3,i,x]->[0,s,1,t,2,i,x]: t=theta(2,i)}");

   union_in1s.push_back("[nt]->{[0,s,1,i,x]->[0,s,1,t,0,i,x]: t=theta(0,i)} union {[0,s,2,i,x]->[0,s,1,t,1,i,x]: t=theta(1,i)} union {[0,s,3,i,x]->[0,s,1,t,2,i,x]: t=theta(2,i)}");
   union_in2s.push_back("{[0,s,0,i,x]->[0,s,0,t,0,i,x]: t=0 and i=0 and x=0}");
   expected_results.push_back("[nt]->{[0,s,1,i,x]->[0,s,1,t,0,i,x]: t=theta(0,i)} union {[0,s,2,i,x]->[0,s,1,t,1,i,x]: t=theta(1,i)} union {[0,s,3,i,x]->[0,s,1,t,2,i,x]: t=theta(2,i)} union {[0,s,0,i,x]->[0,s,0,t,0,i,x]: t=0 and i=0 and x=0}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,1,i0,0]->[accessRelation1]: accessRelation1=i0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,2,ii0,0]->[accessRelation32]: accessRelation32=inter2(ii0)}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,1,i0,0]->[accessRelation1]: accessRelation1=i0} union {[0,tstep0,2,i0,0]->[accessRelation1]: accessRelation1=inter2(i0)}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,1,i0,0]->[accessRelation1]: accessRelation1=i0} union {[0,tstep0,2,i0,0]->[accessRelation1]: accessRelation1=inter2(i0)}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,2,ii0,0]->[accessRelation31]: accessRelation31=inter1(ii0)}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,1,i0,0]->[accessRelation1]: accessRelation1=i0} union {[0,tstep0,2,i0,0]->[accessRelation1]: accessRelation1=inter1(i0)} union {[0,tstep0,2,i0,0]->[accessRelation1]: accessRelation1=inter2(i0)}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,3,i0,0]->[accessRelation1]: accessRelation1=i0}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,1,i0,0]->[accessRelation1]: accessRelation1=i0} union {[0,tstep0,2,i0,0]->[accessRelation1]: accessRelation1=inter1(i0)} union {[0,tstep0,2,i0,0]->[accessRelation1]: accessRelation1=inter2(i0)}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,3,i0,0]->[accessRelation1]: accessRelation1=i0} union {[0,tstep0,1,i0,0]->[accessRelation1]: accessRelation1=i0} union {[0,tstep0,2,i0,0]->[accessRelation1]: accessRelation1=inter1(i0)} union {[0,tstep0,2,i0,0]->[accessRelation1]: accessRelation1=inter2(i0)}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,s,1,i,0]->[sigma_out]: sigma_out=i}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,s,2,i,0]->[sigma_out]: sigma_out=sigma_inter2(i)}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,s,2,i,0]->[sigma_out]: sigma_out=sigma_inter2(i)} union {[0,s,1,i,0]->[sigma_out]: sigma_out=i}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,s,2,i,0]->[sigma_out]: sigma_out=sigma_inter2(i)} union {[0,s,1,i,0]->[sigma_out]: sigma_out=i}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,s,2,i,0]->[sigma_out]: sigma_out=sigma_inter1(i)}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,s,2,i,0]->[sigma_out]: sigma_out=sigma_inter2(i)} union {[0,s,1,i,0]->[sigma_out]: sigma_out=i} union {[0,s0,2,i,0]->[sigma_out]: sigma_out=sigma_inter1(i)}");

   union_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,s,2,i,0]->[sigma_out]: sigma_out=sigma_inter2(i)} union {[0,s,1,i,0]->[sigma_out]: sigma_out=i} union {[0,s,2,i,0]->[sigma_out]: sigma_out=sigma_inter1(i)}");
   union_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,s,3,i,0]->[sigma_out]: sigma_out=i}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,s,2,i,0]->[sigma_out]: sigma_out=sigma_inter2(i)} union {[0,s,1,i,0]->[sigma_out]: sigma_out=i} union {[0,s,3,i,0]->[sigma_out]: sigma_out=i} union {[0,s,2,i,0]->[sigma_out]: sigma_out=sigma_inter1(i)}");

   //Make sure there are equal numbers of inputs
   ASSERT_EQ(union_in1s.size(),union_in2s.size());
   ASSERT_EQ(union_in2s.size(),expected_results.size());

   for(int i=0; i<union_in1s.size(); i++) {
      Relation union_in1(union_in1s[i]);
      Relation union_in2(union_in2s[i]);
      Relation result(union_in1.Union(union_in2));
      Relation expected_result(expected_results[i]);

      ASSERT_EQ(result,expected_result) <<
         union_in1.get_isl() << endl << ".Union(" << union_in2.get_isl() <<
         ") !=" << expected_result.get_isl();
   }
}

TEST(MoldynRealTest,apply_tests){
   //These tests were taken from a full run of the Python version of IEGen using
   //the moldyn_full computation applying transformations up to sparse loop
   vector<string> apply_set_ins,apply_rel_ins,expected_results;

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep]->{[tstep,i]: n_moles>=1+i and tstep>=0 and i>=0 and n_tstep>=tstep+1}");
   apply_rel_ins.push_back("[n_inter,n_moles,n_tstep]->{[tstep,i]->[0,tstep,1,i,0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep]->{[tstep]: tstep>=0 and n_tstep>=tstep+1}");
   apply_rel_ins.push_back("[n_inter,n_moles,n_tstep]->{[tstep]->[0,tstep,0,0,0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,0,0]: n_tstep>=1+tstep0 and tstep0>=0}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep]->{[tstep,ii]: tstep>=0 and n_inter>=1+ii and ii>=0 and n_tstep>=tstep+1}");
   apply_rel_ins.push_back("[n_inter,n_moles,n_tstep]->{[tstep,ii]->[0,tstep,2,ii,0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,2,ii0,0]: n_tstep>=1+tstep0 and tstep0>=0 and ii0>=0 and n_inter>=1+ii0}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep]->{[tstep,i]: n_moles>=1+i and tstep>=0 and i>=0 and n_tstep>=tstep+1}");
   apply_rel_ins.push_back("[n_inter,n_moles,n_tstep]->{[tstep,i]->[0,tstep,3,i,0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0>=0 and n_inter>=1+i0}");
   apply_rel_ins.push_back("[n_inter,n_moles,n_tstep]->{[0,s,2,ii,x]->[ii]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[ii]: n_tstep>=1 and ii>=0 and n_inter>=ii+1}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0>=0 and n_inter>=1+i0}");
   apply_rel_ins.push_back("[n_inter,n_moles,n_tstep]->{[x,s,2,i,y]->[i]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[i0]: n_tstep>=1 and i0>=0 and n_inter>=i0+1}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0>=0 and n_inter>=1+i0}");
   apply_rel_ins.push_back("[n_inter,n_moles,n_tstep]->{[x,s,2,i,y]->[i]: c2=2}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[i0]: n_tstep>=1 and i0>=0 and n_inter>=i0+1}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and 0=i0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0>=0 and n_inter>=1+i0}");
   apply_rel_ins.push_back("[n_inter,n_moles,n_tstep]->{[x,s,2,i,y]->[i]: c2=2}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[i0]: n_tstep>=1 and i0>=0 and n_inter>=i0+1}");

   /*apply_set_ins.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,0,i0,0]: n_tstep>=1+tstep0 and i0=0 and tstep0>=0} union {[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0} union {[0,tstep0,2,i0,0]: n_tstep>=1+tstep0 and tstep0>=0 and i0>=0 and n_inter>=1+i0}");
   apply_rel_ins.push_back("{[x,s,y,i,z]->[y,i]: y=3} union {[x,s,y,i,z]->[y,i]: y=2} union {[x,s,y,i,z]->[y,i]: y=1}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[y,i]: n_moles>=1+i and 1=y and i>=0 and n_tstep>=1} union {[y,i]: n_moles>=1+i and n_tstep>=1 and i>=0 and y=3} union {[y,i]: 2=y and i>=0 and n_inter>=1+i and n_tstep>=1}");*/

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,1,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   apply_rel_ins.push_back("[nt]->{[0,s0,1,i,x]->[0,s0,1,t,0,i,x]: t=theta(0,i)} union {[0,s0,2,i,x]->[0,s0,1,t,1,i,x]: t=theta(1,i)} union {[0,s0,3,i,x]->[0,s0,1,t,2,i,x]: t=theta(2,i)} union {[0,s0,0,i,x]->[0,s0,0,t,0,i,x]: 0=t and 0=i and 0=x}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,0,0,0]: n_tstep>=1+tstep0 and tstep0>=0}");
   apply_rel_ins.push_back("[nt]->{[0,s0,1,i,x]->[0,s0,1,t,0,i,x]: t=theta(0,i)} union {[0,s0,2,i,x]->[0,s0,1,t,1,i,x]: t=theta(1,i)} union {[0,s0,3,i,x]->[0,s0,1,t,2,i,x]: t=theta(2,i)} union {[0,s0,0,i,x]->[0,s0,0,t,0,i,x]: 0=i and 0=x and 0=t}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i,x]: n_tstep>=1+s0 and 0=t and 0=i and 0=x and s0>=0}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,2,ii0,0]: n_tstep>=1+tstep0 and tstep0>=0 and ii0>=0 and n_inter>=1+ii0}");
   apply_rel_ins.push_back("[nt]->{[0,s0,1,i,x]->[0,s0,1,t,0,i,x]: t=theta(0,i)} union {[0,s0,2,i,x]->[0,s0,1,t,1,i,x]: t=theta(1,i)} union {[0,s0,3,i,x]->[0,s0,1,t,2,i,x]: t=theta(2,i)} union {[0,s0,0,i,x]->[0,s0,0,t,0,i,x]: 0=i and 0=x and 0=t}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,3,i0,0]: n_moles>=1+i0 and n_tstep>=1+tstep0 and i0>=0 and tstep0>=0}");
   apply_rel_ins.push_back("[nt]->{[0,s0,1,i,x]->[0,s0,1,t,0,i,x]: t=theta(0,i)} union {[0,s0,2,i,x]->[0,s0,1,t,1,i,x]: t=theta(1,i)} union {[0,s0,3,i,x]->[0,s0,1,t,2,i,x]: t=theta(2,i)} union {[0,s0,0,i,x]->[0,s0,0,t,0,i,x]: 0=i and 0=x and 0=t}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,2,i0,x0]: i0>=0 and n_moles>=1+i0 and n_tstep>=1+s0 and t=theta(2,i0) and s0>=0 and 0=x0}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");
   apply_rel_ins.push_back("{[0,s0,1,t,0,i0,x0]->[s0,t,i0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s,t,i]: n_tstep>=s+1 and s>=0 and n_moles>=1+i and theta(0,i)=t and i>=0}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,0,i0,x0]: n_moles>=1+i0 and i0>=0 and t=theta(0,i0) and n_tstep>=1+s0 and 0=x0 and s0>=0}");
   apply_rel_ins.push_back("{[0,s0,1,t,0,i0,x0]->[s0,t,i0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s0,t,i0]: n_tstep>=s0+1 and s0>=0 and n_moles>=1+i0 and t=theta(0,i0) and i0>=0}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0}");
   apply_rel_ins.push_back("{[0,s0,0,t,0,i0,x0]->[s0,t,i0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s,t,i]: s>=0 and 0=t and 0=i and n_tstep>=s+1}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: n_tstep>=1+s0 and 0=t and 0=i0 and 0=x0 and s0>=0}");
   apply_rel_ins.push_back("{[0,s0,0,t,0,i0,x0]->[s0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s0]: s0>=0 and n_tstep>=s0+1}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)}");
   apply_rel_ins.push_back("{[0,s0,1,t,1,i0,x0]->[s0,t,i0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s,t,i]: s>=0 and n_tstep>=s+1 and n_inter>=1+i and theta(1,i)=t and i>=0}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,1,i0,x0]: i0>=0 and n_tstep>=1+s0 and n_inter>=1+i0 and 0=x0 and s0>=0 and t=theta(1,i0)}");
   apply_rel_ins.push_back("{[0,s0,1,t,1,i0,x0]->[s0,t,i0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s0,t,i0]: s0>=0 and n_tstep>=s0+1 and n_inter>=1+i0 and t=theta(1,i0) and i0>=0}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,2,i0,x0]: i0>=0 and n_moles>=1+i0 and n_tstep>=1+s0 and t=theta(2,i0) and s0>=0 and 0=x0}");
   apply_rel_ins.push_back("{[0,s0,1,t,2,i0,x0]->[s0,t,i0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s,t,i]: n_tstep>=s+1 and s>=0 and n_moles>=1+i and theta(2,i)=t and i>=0}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,2,i0,x0]: i0>=0 and n_moles>=1+i0 and n_tstep>=1+s0 and t=theta(2,i0) and s0>=0 and 0=x0}");
   apply_rel_ins.push_back("{[0,s0,1,t,2,i0,x0]->[s0,t,i0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s0,t,i0]: n_tstep>=s0+1 and s0>=0 and n_moles>=1+i0 and theta(2,i0)=t and i0>=0}");

   apply_set_ins.push_back("{[s0,s1]}");
   apply_rel_ins.push_back("[n_inter,n_moles,n_tstep,nt]->{[tstep,i]->[0,s0,1,t,0,i,x]: tstep=s0 and t=theta(0,i) and 0=x}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,0,i0,x0]: t=theta(0,i0) and 0=x0}");

   apply_set_ins.push_back("{[s0]}");
   apply_rel_ins.push_back("[n_inter,n_moles,n_tstep,nt]->{[tstep]->[0,s0,0,t,0,i0,x0]: 0=i0 and 0=x0 and tstep=s0 and 0=t}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,0,t,0,i0,x0]: 0=x0 and 0=t and 0=i0}");

   apply_set_ins.push_back("{[s0,s1]}");
   apply_rel_ins.push_back("[n_inter,n_moles,n_tstep,nt]->{[tstep,ii]->[0,s0,1,t,1,ii,x0]: tstep=s0 and 0=x0 and t=theta(1,ii)}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,1,i0,x0]: t=theta(1,i0) and 0=x0}");

   apply_set_ins.push_back("{[s0,s1]}");
   apply_rel_ins.push_back("[n_inter,n_moles,n_tstep,nt]->{[tstep,i]->[0,s0,1,t,2,i,x0]: tstep=s0 and t=theta(2,i) and 0=x0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,2,i0,x0]: 0=x0 and t=theta(2,i0)}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep,nt]->{[s0,t,i0]: i0>=0 and nt>=1+t and s0>=0 and n_moles>=1+i0 and n_tstep>=s0+1 and t>=0}");
   apply_rel_ins.push_back("{[s0,t,i0]->[s0,t]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s0,t]: nt>=1+t and t>=0 and n_moles>=1 and s0>=0 and n_tstep>=s0+1}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep,nt]->{[s0,t,i0]: i0>=0 and nt>=1+t and s0>=0 and n_tstep>=s0+1 and t>=0 and n_inter>=1+i0}");
   apply_rel_ins.push_back("{[s0,t,i0]->[s0,t]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s0,t]: nt>=1+t and t>=0 and s0>=0 and n_inter>=1 and n_tstep>=s0+1}");

   apply_set_ins.push_back("[n_inter,n_moles,n_tstep,nt]->{[s0,t,i0]: i0>=0 and nt>=1+t and s0>=0 and n_moles>=1+i0 and n_tstep>=s0+1 and t>=0}");
   apply_rel_ins.push_back("{[s0,t,i0]->[s0,t]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s0,t]: nt>=1+t and t>=0 and n_moles>=1 and s0>=0 and n_tstep>=s0+1}");

   //Make sure there are equal numbers of inputs
   ASSERT_EQ(apply_set_ins.size(),apply_rel_ins.size());
   ASSERT_EQ(apply_rel_ins.size(),expected_results.size());

   for(int i=0; i<apply_set_ins.size(); i++) {
      Set apply_set_in(apply_set_ins[i]);
      Relation apply_rel_in(apply_rel_ins[i]);
      Set result(apply_rel_in.Apply(apply_set_in));
      Set expected_result(expected_results[i]);

      ASSERT_EQ(result,expected_result) <<
         apply_rel_in.get_isl() << endl << ".Apply(" << apply_set_in.get_isl() <<
         ") !=" << expected_result.get_isl();
   }
}

TEST(MoldynRealTest,inverse_tests){
   //These tests were taken from a full run of the Python version of IEGen using
   //the moldyn_full computation applying transformations up to sparse loop
   vector<string> inverse_rels,expected_results;

   inverse_rels.push_back("[n_inter,n_moles,n_tstep]->{[tstep,i]->[0,tstep,1,i,0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,1,i0,0]->[tstep0,i0]}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep]->{[tstep,i]->[0,tstep,2,i,0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep,2,i,0]->[tstep,i]}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep]->{[tstep,i]->[0,tstep,2,i,0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep,2,i,0]->[tstep,i]}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep]->{[tstep,i]->[0,tstep,3,i,0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep,3,i,0]->[tstep,i]}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep,3,i,0]->[accessRelation1] : accessRelation1-i=0} union {[0,tstep,1,i,0]->[accessRelation1] : accessRelation1-i=0}  union {[0,tstep,2,i,0]->[accessRelation1] : accessRelation1-inter1(i)=0} union {[0,tstep,2,i,0]->[accessRelation1]: accessRelation1-inter2(i)=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[accessRelation1]->[0,tstep,3,i,0] : accessRelation1-i=0} union {[accessRelation1]->[0,tstep,1,i,0] : accessRelation1-i=0} union {[accessRelation1]->[0,tstep,2,i,0] : accessRelation1-inter2(i)=0} union {[accessRelation1]->[0,tstep,2,i,0] : accessRelation1-inter1(i)=0}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep]->{[accessRelation1]->[i] : accessRelation1-inter1(i)=0} union {[accessRelation1]->[i] : accessRelation1-inter2(i)=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[i]->[accessRelation1] : accessRelation1-inter2(i)=0} union {[i]->[accessRelation1] : accessRelation1-inter1(i)=0}");

   inverse_rels.push_back("{[sigma_in]->[sigma_out] : sigma_out-sigma(sigma_in)=0}");
   expected_results.push_back("{[sigma_out]->[sigma_in] : sigma_out-sigma(sigma_in)=0}");

   inverse_rels.push_back("{[0,s,2,i,x]->[0,s,2,i,x]} union {[0,s,3,i,j]->[0,s,3,x,j] : x-sigma(i)=0} union {[0,s,1,i,j]->[0,s,1,x,j] : x-sigma(i)=0 and j=0} union {[0,s,0,x,i]->[0,s,1,x,i]: x=0 and i=0}");
   expected_results.push_back("{[0,s,1,x,j]->[0,s,1,i,j] : x-sigma(i)=0 and j=0} union {[0,s,1,x,i]->[0,s,0,x,i]: x=0 and i=0} union {[0,s,2,i,x]->[0,s,2,i,x]} union {[0,s,3,x,j]->[0,s,3,i,j] : x-sigma(i)=0}");

   inverse_rels.push_back("{[0,s,2,x,y]->[0,s,2,x,y]} union {[0,s,3,i,x]->[0,s,3,y,x] : y-sigma(i)=0} union {[0,s,1,i,x]->[0,s,1,y,x] : x=0 and y-sigma(i)=0} union {[0,s,0,i,x]->[0,s,0,i,x] : x=0 and i=0}");
   expected_results.push_back("{[0,s,1,y,x]->[0,s,1,i,x] : y-sigma(i)=0 and x=0} union {[0,s,0,i,x]->[0,s,0,i,x] : x=0 and i=0} union {[0,s,2,i,x]->[0,s,2,i,x]} union {[0,s,3,y,x]->[0,s,3,i,x] : y-sigma(i)=0}");

   inverse_rels.push_back("{[0,s,2,i,x]->[0,s,2,i,x]} union {[0,s,3,i,x]->[0,s,3,y,x] : y-sigma(i)=0} union {[0,s,1,i,x]->[0,s,1,y,x] : x=0 and y-sigma(i)=0} union {[0,s,0,i,x]->[0,s,0,i,x] : x=0 and i=0}");
   expected_results.push_back("{[0,s,1,y,x]->[0,s,1,i,x] : x=0 and y-sigma(i)=0} union {[0,s,0,i,x]->[0,s,0,i,x] : x=0 and i=0} union {[0,s,2,i,x]->[0,s,2,i,x]} union {[0,s,3,y,x]->[0,s,3,i,x] : y-sigma(i)=0}");

   inverse_rels.push_back("{[0,s,2,i,x]->[0,s,2,i,x]} union {[0,s,3,i,x]->[0,s,3,y,x] : y-sigma(i)=0} union {[0,s,1,i,x]->[0,s,1,y,x] : x=0 and y-sigma(i)=0} union {[0,s,0,i,x]->[0,s,0,i,x] : x=0 and i=0}");
   expected_results.push_back("{[0,s,1,y,x]->[0,s,1,i,x] : x=0 and y-sigma(i)=0} union {[0,s,0,i,x]->[0,s,0,i,x] : x=0 and i=0} union {[0,s,2,i,x]->[0,s,2,i,x]} union {[0,s,3,y,x]->[0,s,3,i,x] : y-sigma(i)=0}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep]->{[0,s,2,i,0]->[sigma_out] : sigma_out-sigma_inter2(i)=0} union {[0,s,1,i,0]->[sigma_out] : i-sigma_out=0} union {[0,s,3,i,0]->[sigma_out] : i-sigma_out=0} union {[0,s,2,i,0]->[sigma_out] : sigma_out-sigma_inter1(i)=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[sigma_out]->[0,s,1,i,0] : i-sigma_out=0} union {[sigma_out]->[0,s,2,i,0] : sigma_out-sigma_inter1(i)=0} union {[sigma_out]->[0,s,3,i,0] : i-sigma_out=0} union {[sigma_out]->[0,s,2,i,0] : sigma_out-sigma_inter2(i)=0}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep]->{[sigma_out]->[i0] : sigma_out-sigma_inter1(i0)=0} union {[sigma_out]->[i0] : sigma_out-sigma_inter2(i0)=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[i0]->[sigma_out] : sigma_out-sigma_inter1(i0)=0} union {[i0]->[sigma_out] : sigma_out-sigma_inter2(i0)=0}");

   inverse_rels.push_back("{[delta_in]->[delta_out] : delta_out-delta(delta_in)=0}");
   expected_results.push_back("{[delta_out]->[delta_in] : delta_out-delta(delta_in)=0}");

   inverse_rels.push_back("{[0,s,2,i,x]->[0,s,2,y,x] : y-delta(i)=0} union {[0,s,1,i,x]->[0,s,1,i,x] : x=0} union {[0,s,3,i,x]->[0,s,3,i,x]} union {[0,s,0,i,x]->[0,s,0,i,x] : x=0 and i=0}");
   expected_results.push_back("{[0,s,0,i,x]->[0,s,0,i,x] : i=0 and x=0} union {[0,s,3,i,x]->[0,s,3,i,x]} union {[0,s,2,y,x]->[0,s,2,i,x] : y-delta(i)=0} union {[0,s,1,i,x]->[0,s,1,i,x] : x=0}");

   inverse_rels.push_back("{[0,s,2,i,x]->[0,s,2,y,x] : y-delta(i)=0} union {[0,s,1,i,x]->[0,s,1,i,x] : x=0} union {[0,s,3,i,x]->[0,s,3,i,x]} union {[0,s,0,i,x]->[0,s,0,i,x] : i=0 and x=0}");
   expected_results.push_back("{[0,s,0,i,x]->[0,s,0,i,x] : i=0 and x=0} union {[0,s,3,i,x]->[0,s,3,i,x]} union {[0,s,2,y,x]->[0,s,2,i,x] : y-delta(i)=0} union {[0,s,1,i,x]->[0,s,1,i,x] : x=0}");

   inverse_rels.push_back("{[0,s,2,i,x]->[0,s,2,y,x] : y-delta(i)=0} union {[0,s,1,i,x]->[0,s,1,i,x] : x=0} union {[0,s,3,i,x]->[0,s,3,i,x]} union {[0,s,0,i,x]->[0,s,0,i,x] : x=0 and i=0}");
   expected_results.push_back("{[0,s,0,i,x]->[0,s,0,i,x] : i=0 and x=0} union {[0,s,3,i,x]->[0,s,3,i,x]} union {[0,s,2,y,x]->[0,s,2,i,x] : y-delta(i)=0} union {[0,s,1,i,x]->[0,s,1,i,x] : x=0}");

   inverse_rels.push_back("{[0,s,2,i,x]->[0,s,2,y,x] : y-delta(i)=0} union {[0,s,1,i,x]->[0,s,1,i,x] : x=0} union {[0,s,3,i,x]->[0,s,3,i,x]} union {[0,s,0,i,x]->[0,s,0,i,x] : x=0 and i=0}");
   expected_results.push_back("{[0,s,0,i,x]->[0,s,0,i,x] : x=0 and i=0} union {[0,s,3,i,x]->[0,s,3,i,x]} union {[0,s,2,y,x]->[0,s,2,i,x] : y-delta(i)=0} union {[0,s,1,i,x]->[0,s,1,i,x] : x=0}");

   inverse_rels.push_back("[nt]->{[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : c10-1=0 and c1-1=0 and x-x0=0 and t-theta(0,i)=0 and s-s0=0 and i-i0=0 and c01=0 and c00=0 and c0=0} union {[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : c1-2=0 and c10-1=0 and c01-1=0 and x-x0=0 and t-theta(1,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union {[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : c1-3=0 and c01-2=0 and c10-1=0 and x-x0=0 and t-theta(2,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union {[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : x0=0 and x=0 and t=0 and s-s0=0 and i0=0 and i=0 and c10=0 and c1=0 and c01=0 and c00=0 and c0=0}");
   expected_results.push_back("[nt]->{[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : c1-3=0 and c01-2=0 and c10-1=0 and x-x0=0 and t-theta(2,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union {[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : c1-2=0 and c10-1=0 and c01-1=0 and x-x0=0 and t-theta(1,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union {[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : c10-1=0 and c1-1=0 and x-x0=0 and t-theta(0,i)=0 and s-s0=0 and i-i0=0 and c01=0 and c00=0 and c0=0} union {[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : x0=0 and x=0 and t=0 and s-s0=0 and i0=0 and i=0 and c10=0 and c1=0 and c01=0 and c00=0 and c0=0}");

   inverse_rels.push_back("[nt]->{[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : c10-1=0 and c1-1=0 and x-x0=0 and t-theta(0,i)=0 and s-s0=0 and i-i0=0 and c01=0 and c00=0 and c0=0} union {[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : c1-2=0 and c10-1=0 and c01-1=0 and x-x0=0 and t-theta(1,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union {[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : c1-3=0 and c01-2=0 and c10-1=0 and x-x0=0 and t-theta(2,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union {[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : x0=0 and x=0 and t=0 and s-s0=0 and i0=0 and i=0 and c10=0 and c1=0 and c01=0 and c00=0 and c0=0}");
   expected_results.push_back("[nt]->{[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : c1-3=0 and c01-2=0 and c10-1=0 and x-x0=0 and t-theta(2,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union {[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : c1-2=0 and c10-1=0 and c01-1=0 and x-x0=0 and t-theta(1,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union {[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : c10-1=0 and c1-1=0 and x-x0=0 and t-theta(0,i)=0 and s-s0=0 and i-i0=0 and c01=0 and c00=0 and c0=0} union {[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : x0=0 and x=0 and t=0 and s-s0=0 and i0=0 and i=0 and c10=0 and c1=0 and c01=0 and c00=0 and c0=0}");

   inverse_rels.push_back("[nt]->{[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : c10-1=0 and c1-1=0 and x-x0=0 and t-theta(0,i)=0 and s-s0=0 and i-i0=0 and c01=0 and c00=0 and c0=0} union {[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : c1-2=0 and c10-1=0 and c01-1=0 and x-x0=0 and t-theta(1,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union {[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : c1-3=0 and c01-2=0 and c10-1=0 and x-x0=0 and t-theta(2,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union {[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : x0=0 and x=0 and t=0 and s-s0=0 and i0=0 and i=0 and c10=0 and c1=0 and c01=0 and c00=0 and c0=0}");
   expected_results.push_back("[nt]->{[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : c1-3=0 and c01-2=0 and c10-1=0 and x-x0=0 and t-theta(2,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union {[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : c1-2=0 and c10-1=0 and c01-1=0 and x-x0=0 and t-theta(1,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union {[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : c10-1=0 and c1-1=0 and x-x0=0 and t-theta(0,i)=0 and s-s0=0 and i-i0=0 and c01=0 and c00=0 and c0=0} union {[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : x0=0 and x=0 and t=0 and s-s0=0 and i0=0 and i=0 and c10=0 and c1=0 and c01=0 and c00=0 and c0=0}");

   inverse_rels.push_back("[nt]->{[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : c10-1=0 and c1-1=0 and x-x0=0 and t-theta(0,i)=0 and s-s0=0 and i-i0=0 and c01=0 and c00=0 and c0=0} union {[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : c1-2=0 and c10-1=0 and c01-1=0 and x-x0=0 and t-theta(1,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union {[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : c1-3=0 and c01-2=0 and c10-1=0 and x-x0=0 and t-theta(2,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union  {[c0,s,c1,i,x]->[c00,s0,c10,t,c01,i0,x0] : x0=0 and x=0 and t=0 and s-s0=0 and i0=0 and i=0 and c10=0 and c1=0 and c01=0 and c00=0 and c0=0}");
   expected_results.push_back("[nt]->{[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : c1-3=0 and c01-2=0 and c10-1=0 and x-x0=0 and t-theta(2,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union {[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : c1-2=0 and c10-1=0 and c01-1=0 and x-x0=0 and t-theta(1,i)=0 and s-s0=0 and i-i0=0 and c00=0 and c0=0} union {[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : c10-1=0 and c1-1=0 and x-x0=0 and t-theta(0,i)=0 and s-s0=0 and i-i0=0 and c01=0 and c00=0 and c0=0} union {[c00,s0,c10,t,c01,i0,x0]->[c0,s,c1,i,x] : x0=0 and x=0 and t=0 and s-s0=0 and i0=0 and i=0 and c10=0 and c1=0 and c01=0 and c00=0 and c0=0}");

   inverse_rels.push_back("{[s0,t,i0]->[c00,s,c10,t,c01,i,x0]}");
   expected_results.push_back("{[c00,s,c10,t,c01,i,x0]->[s0,t,i0]}");

   inverse_rels.push_back("{[s]->[c00,s,c10,t,c01,i0,x0]}");
   expected_results.push_back("{[c00,s,c10,t,c01,i0,x0]->[s]}");

   inverse_rels.push_back("{[s,t,i]->[c00,s,c10,t,c01,i,x0]}");
   expected_results.push_back("{[c00,s,c10,t,c01,i,x0]->[s,t,i]}");

   inverse_rels.push_back("{[s,t,i]->[c00,s,c10,t,c01,i,x0]}");
   expected_results.push_back("{[c00,s,c10,t,c01,i,x0]->[s,t,i]}");

   inverse_rels.push_back(" [n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,0,i0,0]->[sigma_out] : t-theta(0,i0)=0 and i0-sigma_out=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[sigma_out]->[0,s0,1,t,0,i0,0] : t-theta(0,i0)=0 and i0-sigma_out=0}");

   inverse_rels.push_back(" [n_inter,n_moles,n_tstep,nt]->{[sigma_out]->[s0,t,i0] : t-theta(0,sigma_out)=0 and i0-sigma_out=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s0,t,i0]->[sigma_out] : t-theta(0,sigma_out)=0 and i0-sigma_out=0}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,1,i0,0]->[sigma_out] : t-theta(1,i0)=0 and sigma_out-sigma_inter2_delta_inv(i0)=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[sigma_out]->[0,s0,1,t,1,i0,0] : t-theta(1,i0)=0 and sigma_out-sigma_inter2_delta_inv(i0)=0}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep,nt]->{[sigma_out]->[s0,t,i0] : t-theta(1,i0)=0 and sigma_out-sigma_inter2_delta_inv(i0)=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s0,t,i0]->[sigma_out] : t-theta(1,i0)=0 and sigma_out-sigma_inter2_delta_inv(i0)=0}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,1,i0,0]->[sigma_out] : t-theta(1,i0)=0 and sigma_out-sigma_inter1_delta_inv(i0)=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[sigma_out]->[0,s0,1,t,1,i0,0] : t-theta(1,i0)=0 and sigma_out-sigma_inter1_delta_inv(i0)=0}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep,nt]->{[sigma_out]->[s0,t,i0] : t-theta(1,i0)=0 and sigma_out-sigma_inter1_delta_inv(i0)=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s0,t,i0]->[sigma_out] : t-theta(1,i0)=0 and sigma_out-sigma_inter1_delta_inv(i0)=0}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s0,1,t,2,i0,0]->[sigma_out] : t-theta(2,i0)=0 and i0-sigma_out=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[sigma_out]->[0,s0,1,t,2,i0,0] : t-theta(2,i0)=0 and i0-sigma_out=0}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep,nt]->{[sigma_out]->[s0,t,i0] : t-theta(2,sigma_out)=0 and i0-sigma_out=0}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s0,t,i0]->[sigma_out] : t-theta(2,sigma_out)=0 and i0-sigma_out=0}");

   inverse_rels.push_back("{[s,t]->[s,t,i0]}");
   expected_results.push_back("{[s,t,i0]->[s,t]}");

   inverse_rels.push_back("{[c00,s00,c10,t0,c01]->[c00,s00,c10,t0,c01,i00,x0]}");
   expected_results.push_back("{[c00,s00,c10,t0,c01,i00,x0]->[c00,s00,c10,t0,c01]}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep,nt]->{[s,t,i0]->[0,s,1,t,0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s,1,t,0]->[s,t,i0]}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s,1,t,0]->[s,t]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s,t]->[0,s,1,t,0]}");

   inverse_rels.push_back("{[]->[s0]}");
   expected_results.push_back("{[s0]->[]}");

   inverse_rels.push_back("{[c00,s,c10,t,c01]->[c00,s,c10,t,c01,i0,x0]}");
   expected_results.push_back("{[c00,s,c10,t,c01,i0,x0]->[c00,s,c10,t,c01]}");

   inverse_rels.push_back("{[s,t]->[s,t,i0]}");
   expected_results.push_back("{[s,t,i0]->[s,t]}");

   inverse_rels.push_back("{[c00,s,c10,t,c01]->[c00,s,c10,t,c01,i00,x0]}");
   expected_results.push_back("{[c00,s,c10,t,c01,i00,x0]->[c00,s,c10,t,c01]}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep,nt]->{[s,t,i0]->[0,s,1,t,1]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s,1,t,1]->[s,t,i0]}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s,1,t,1]->[s,t]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s,t]->[0,s,1,t,1]}");

   inverse_rels.push_back("{[s,t]->[s,t,i0]}");
   expected_results.push_back("{[s,t,i0]->[s,t]}");

   inverse_rels.push_back("{[c00,s,c10,t,c01]->[c00,s,c10,t,c01,i00,x0]}");
   expected_results.push_back("{[c00,s,c10,t,c01,i00,x0]->[c00,s,c10,t,c01]}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep,nt]->{[s,t,i0]->[0,s,1,t,2]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s,1,t,2]->[s,t,i0]}");

   inverse_rels.push_back("[n_inter,n_moles,n_tstep,nt]->{[0,s,1,t,2]->[s,t]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[s,t]->[0,s,1,t,2]}");

   //Make sure there are equal numbers of inputs
   ASSERT_EQ(inverse_rels.size(),expected_results.size());

   for(int i=0; i<inverse_rels.size(); i++) {
      Relation inverse_rel(inverse_rels[i]);
      Relation result(inverse_rel.Inverse());
      Relation expected_result(expected_results[i]);

      ASSERT_EQ(result,expected_result) <<
         inverse_rel.get_isl() << ".Inverse()" << endl <<
         "!=" << expected_result.get_isl();
   }
}

TEST(MoldynRealTest,compose_tests){
   //These tests were taken from a full run of the Python version of IEGen using
   //the moldyn_full computation applying transformations up to sparse loop
   vector<string> compose_in1s,compose_in2s,expected_results;

   compose_in1s.push_back("[n_tstep]->{[tstep,i]->[accessRelation1]: accessRelation1=i}");
   compose_in2s.push_back("{[0,tstep0,1,i0,0]->[tstep0,i0]}");
   expected_results.push_back("[n_tstep]->{[0,tstep0,1,i0,0]->[accessRelation1]: accessRelation1=i0}");

   compose_in1s.push_back("{[tstep,ii]->[accessRelation32]: accessRelation32=inter2(ii)}");
   compose_in2s.push_back("{[0,tstep,2,ii,0]->[tstep,ii]}");
   expected_results.push_back("{[0,tstep0,2,ii0,0]->[accessRelation32]: accessRelation32=inter2(ii0)}");

   compose_in1s.push_back("{[tstep,ii]->[accessRelation31]: accessRelation31=inter1(ii)}");
   compose_in2s.push_back("{[0,tstep0,2,ii0,0]->[tstep0,ii0]}");
   expected_results.push_back("{[0,tstep0,2,ii0,0]->[accessRelation31]: accessRelation31=inter1(ii0)}");

   compose_in1s.push_back("{[tstep,i]->[accessRelation43]: accessRelation43=i}");
   compose_in2s.push_back("{[0,tstep0,3,i0,0]->[tstep0,i0]}");
   expected_results.push_back("{[0,tstep0,3,i0,0]->[accessRelation43]: accessRelation43=i0}");

   compose_in1s.push_back("{[0,s,2,ii,x]->[ii]}");
   compose_in2s.push_back("{[accessRelation1]->[0,tstep0,1,i0,0]: accessRelation1=i0} union {[accessRelation1]->[0,tstep0,2,i0,0]: accessRelation1=inter2(i0)} union {[accessRelation1]->[0,tstep0,2,i0,0]: accessRelation1=inter1(i0)} union {[accessRelation1]->[0,tstep0,3,i0,0]: accessRelation1=i0}");
   expected_results.push_back("{[accessRelation1]->[ii0]: accessRelation1=inter1(ii0)} union {[accessRelation1]->[ii0]: accessRelation1=inter2(ii0)}");

   compose_in1s.push_back("{[sigma_in]->[sigma_out]: sigma_out=sigma(sigma_in)}");
   compose_in2s.push_back("{[0,tstep0,1,i0,0]->[accessRelation1]: accessRelation1=i0}");
   expected_results.push_back("{[0,tstep0,1,i0,0]->[sigma_out]: sigma_out=sigma(i0)}");

   compose_in1s.push_back("{[sigma_in]->[sigma_out]: sigma_out=sigma(sigma_in)}");
   compose_in2s.push_back("{[0,tstep0,2,ii0,0]->[accessRelation32]: accessRelation32=inter2(ii0)}");
   expected_results.push_back("{[0,tstep0,2,ii0,0]->[sigma_out]: sigma_out=sigma(inter2(ii0))}");

   compose_in1s.push_back("{[sigma_in]->[sigma_out]: sigma_out=sigma(sigma_in)}");
   compose_in2s.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,2,ii0,0]->[accessRelation31]: accessRelation31=inter1(ii0)}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,tstep0,2,ii0,0]->[sigma_out]: sigma_out=sigma(inter1(ii0))}");

   compose_in1s.push_back("{[sigma_in]->[sigma_out]: sigma_out=sigma(sigma_in)}");
   compose_in2s.push_back("{[0,tstep0,3,i0,0]->[accessRelation43]: accessRelation43=i0}");
   expected_results.push_back("{[0,tstep0,3,i0,0]->[sigma_out]: sigma_out=sigma(i0)}");

   compose_in1s.push_back("{[0,tstep0,1,i0,0]->[sigma_out]: sigma_out=sigma(i0)}");
   compose_in2s.push_back("{[0,s0,1,c04,0]->[0,s0,1,c01,0]: c01=sigma_inv(c04)} union {[0,s0,0,c04,0]->[0,s0,0,c04,0]: 0=c04} union {[0,s0,2,c04,0]->[0,s0,2,c04,0]} union {[0,s0,3,c04,0]->[0,s0,3,c01,0]: c01=sigma_inv(c04)}");
   expected_results.push_back("{[0,s0,1,c04,0]->[sigma_out]: sigma_out-sigma(sigma_inv(c04))=0}");

   compose_in1s.push_back("{[0,tstep0,2,ii0,0]->[sigma_out]: sigma_out=sigma(inter2(ii0))}");
   compose_in2s.push_back("{[0,s0,1,c04,0]->[0,s0,1,c01,0]: c01=sigma_inv(c04)} union {[0,s0,1,c04,0]->[0,s0,1,c04,0]: 0=c04} union {[0,s0,2,c04,0]->[0,s0,2,c04,0]} union {[0,s0,3,c04,0]->[0,s0,3,c01,0]: c01=sigma_inv(c04)}");
   expected_results.push_back("{[0,s0,2,c04,0]->[sigma_out]: sigma_out=sigma(inter2(c04))}");

   compose_in1s.push_back("{[0,tstep0,2,ii0,0]->[sigma_out]: sigma_out=sigma(inter1(ii0))}");
   compose_in2s.push_back("{[0,s0,1,c04,0]->[0,s0,1,c01,0]: c01=sigma_inv(c04)} union {[0,s0,0,c04,0]->[0,s0,0,c01,0]: c1=0 and 0=c04} union {[0,s0,2,c04,0]->[0,s0,2,c04,0]} union {[0,s0,3,c04,0]->[0,s0,3,c01,0]: c01=sigma_inv(c04)}");
   expected_results.push_back("{[0,s0,2,c04,0]->[sigma_out]: sigma_out=sigma(inter1(c04))}");

   compose_in1s.push_back("{[0,tstep0,3,i0,0]->[sigma_out]: sigma_out=sigma(i0)}");
   compose_in2s.push_back("{[0,s0,1,c04,0]->[0,s0,1,c01,0]: c01=sigma_inv(c04)} union {[0,s0,0,c04,0]->[0,s0,0,c01,0]: 0=c01 and 0=c04} union {[0,s0,2,c04,0]->[0,s0,2,c04,0]} union {[0,s0,3,c04,0]->[0,s,3,c01,0]: c01=sigma_inv(c04)}");
   expected_results.push_back("{[0,s0,3,c04,0]->[sigma_out]: sigma_out-sigma(sigma_inv(c04))=0}");

   compose_in1s.push_back("{[x,s,2,i,y]->[i]}");
   compose_in2s.push_back("{[sigma_out]->[0,s0,1,c04,0]: sigma_out=c04} union {[sigma_out]->[0,s0,2,c04,0]: sigma_out=sigma_inter1(c04)} union {[sigma_out]->[0,s0,3,c04,0]: sigma_out=c04} union {[sigma_out]->[0,s0,2,c04,0]: sigma_out=sigma_inter2(c04)}");
   expected_results.push_back("{[sigma_out]->[i0]: sigma_out=sigma_inter1(i0)} union {[sigma_out]->[i0]: sigma_out=sigma_inter2(i0)}");

   compose_in1s.push_back("[n_inter,n_moles,n_tstep]->{[0,s0,1,c04,0]->[sigma_out]: sigma_out=c04}");
   compose_in2s.push_back("{[0,s,0,c04,c05]->[0,s,0,c01,c02]: c05=0 and c05=c02 and c04=c01 and c04=0} union {[0,s,3,c04,c05]->[0,s,3,c01,c02]: c01=c04 and c02=c05 and c02=0} union {[0,s,2,c04,c05]->[0,s,2,c01,c02]: c01=delta_inv(c04) and c02=c05 and c05=0} union {[0,s,1,c04,c02]->[0,s,1,c01,c05]: c01=c04 and c02=0 and c02=c05}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[0,s,1,c04,c05]->[sigma_out]: sigma_out=c04 and c05=0}");

   compose_in1s.push_back("{[0,s0,2,c04,0]->[sigma_out]: sigma_out=sigma_inter2(c04)}");
   compose_in2s.push_back("{[0,s0,0,c04,0]->[0,s0,0,c01,0]: 0=c01 and c04=0} union {[0,s0,3,c04,0]->[0,s0,3,c04,0]} union {[0,s0,2,c04,0]->[0,s0,2,c01,0]: c01=delta_inv(c04)} union {[0,s0,1,c04,0]->[0,s0,1,c04,0]}");
   expected_results.push_back("{[0,s0,2,c04,0]->[sigma_out]: sigma_out=sigma_inter2(delta_inv(c04))}");

   compose_in1s.push_back("{[0,s0,2,c04,0]->[sigma_out]: sigma_out=sigma_inter1(c04)}");
   compose_in2s.push_back("{[0,s0,0,c04,0]->[0,s0,0,c01,0]: 0=c01 and 0=c04} union {[0,s0,3,c04,0]->[0,s0,3,c04,0]} union {[0,s0,2,c04,0]->[0,s0,2,c01,0]: c01=delta_inv(c04)} union {[0,s0,1,c04,0]->[0,s0,1,c04,0]}");
   expected_results.push_back("{[0,s0,2,c04,0]->[sigma_out]: sigma_out=sigma_inter1(delta_inv(c04))}");

   compose_in1s.push_back("{[0,s0,3,c04,0]->[sigma_out]: sigma_out=c04}");
   compose_in2s.push_back("{[0,s0,0,c04,0]->[0,s0,0,c01,0]: 0=c01 and 0=c04} union {[0,s0,3,c04,0]->[0,s0,3,c04,0]} union {[0,s0,2,c04,0]->[0,s0,2,c01,0]: c01=delta_inv(c04)} union {[0,s0,1,c04,0]->[0,s0,1,c04,0]}");
   expected_results.push_back("{[0,s0,3,c04,0]->[sigma_out]: sigma_out=c04}");

   compose_in1s.push_back("{[theta_in0,theta_in1]->[t]: t=theta(theta_in0,theta_in1)}");
   compose_in2s.push_back("[n_inter,n_moles,n_tstep]->{[y0,i0]->[theta_in0,theta_in1]: y0=1 and y0=theta_in0 and theta_in1=i0 and n_moles>=1+i0 and i0>=0 and n_tstep>=1} union {[y0,i0]->[theta_in0,theta_in1]: y0=3 and y0=theta_in0 and theta_in1=i0 and n_moles>=1+i0 and n_tstep>=1 and i0>=0} union {[y0,i0]->[theta_in0,theta_in1]: y0=2 and y0=theta_in0 and theta_in1=i0 and i0>=0 and n_inter>=1+i0 and n_tstep>=1}");
   expected_results.push_back("[n_inter,n_moles,n_tstep]->{[y0,i0]->[t] : y0-3=0 and t-theta(3,i0)=0 and n_tstep-1>=0 and n_moles-i0-1>=0 and i0>=0; [y0,i0]->[t] : y0-2=0 and t-theta(2,i0)=0 and n_tstep-1>=0 and n_inter-i0-1>=0 and i0>=0; [y0,i0]->[t] : y0-1=0 and t-theta(1,i0)=0 and n_tstep-1>=0 and n_moles-i0-1>=0 and i0>=0}");

   /*compose_in1s.push_back("[n_inter,n_moles,n_tstep]->{[theta_in0,theta_in1]->[t]: n_moles>=1+theta_in1 and n_tstep>=1 and theta_in1>=0 and theta_in0=3 and t=theta(theta_in0,theta_in1)} union {[theta_in0,theta_in1]->[t]: n_tstep>=1 and theta_in1>=0 and n_inter>=1+theta_in1 and theta_in0=2 and t=theta(theta_in0,theta_in1)} union {[theta_in0,theta_in1]->[t]: n_moles>=1+theta_in1 and n_tstep>=1 and theta_in1>=0 and theta_in0=1 and t=theta(theta_in0,theta_in1)}");
   compose_in2s.push_back("[nt]->{[tile]: tile>=0 and nt>=tile+1}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[theta_in0,theta_in1]->[t]: n_moles>=1+theta_in1 and t>=0 and nt>=1+t and theta_in1>=0 and t=theta(theta_in0,theta_in1) and n_tstep>=1 and theta_in0=1} union {[theta_in0,theta_in1]->[t]: n_moles>=1+theta_in1 and theta_in0=3 and t>=0 and nt>=1+t and theta_in1>=0 and t=theta(theta_in0,theta_in1) and n_tstep>=1} union {[theta_in0,theta_in1]->[t]: t>=0 and nt>=1+t and theta_in0=2 and theta_in1>=0 and n_inter>=1+theta_in1 and t=theta(theta_in0,theta_in1) and n_tstep>=1}");*/

   compose_in1s.push_back("[nt]->{[0,s0,1,i,x]->[0,s0,1,t,0,i,x]: t=theta(0,i)} union {[0,s0,2,i,x]->[0,s0,1,t,1,i,x]: t=theta(1,i)} union {[0,s0,3,i,x]->[0,s0,1,t,2,i,x]: t=theta(2,i)} union {[0,s0,0,i,x]->[0,s0,0,t,0,i,x]: 0=x and 0=i and 0=t}");
   compose_in2s.push_back("[n_inter,n_moles,n_tstep]->{[tstep,i]->[0,tstep,1,i,0]}");
   expected_results.push_back("[n_inter,n_moles,n_tstep,nt]->{[tstep,i]->[0,tstep,1,t,0,i1,x1] : x1=0 and t-theta(0,i1)=0 and i-i1=0}");

   compose_in1s.push_back("{[0,s0,1,c04,0]->[sigma_out]: sigma_out=c04}");
   compose_in2s.push_back("{[0,s0,1,t,2,i,x]->[0,s0,3,i,x]: t=theta(2,i)} union {[0,s0,1,t,1,i,x]->[0,s0,2,i,x]: t=theta(1,i)} union {[0,s0,1,t,0,i,x]->[0,s0,1,i,x]: t=theta(0,i)} union {[0,s0,0,t,0,i,x]->[0,s0,0,i,x]: t=0}");
   expected_results.push_back("{[0,s0,1,t,0,i0,x0]->[sigma_out]: sigma_out=i0 and t=theta(0,i0) and 0=x0}");

   compose_in1s.push_back("{[0,s0,1,i,x]->[0,s0,1,t,0,i,x]: t=theta(0,i)} union {[0,s0,2,i,x]->[0,s0,1,t,1,i,x]: t=theta(1,i)} union {[0,s0,3,i,x]->[0,s0,1,t,2,i,x]: t=theta(2,i)} union {[0,s0,0,i,x]->[0,s0,0,t,0,i,x]: 0=t}");
   compose_in2s.push_back("{[tstep]->[0,tstep,0,0,0]}");
   expected_results.push_back("{[tstep]->[0,tstep,0,t,0,i0,x0]: 0=i0 and 0=x0 and 0=t}");

   compose_in1s.push_back("{[0,s0,1,i,x]->[0,s0,1,t,0,i,x]: t=theta(0,i)} union {[0,s0,2,i,x]->[0,s0,1,t,1,i,x]: t=theta(1,i)} union {[0,s0,3,i,x]->[0,s0,1,t,2,i,x]: t=theta(2,i)} union {[0,s0,0,i,x]->[0,s0,0,t,0,i,x]: t=0}");
   compose_in2s.push_back("{[tstep,ii]->[0,tstep,2,ii,0]}");
   expected_results.push_back("{[tstep,i0]->[0,tstep,1,t,1,i0,x0]: 0=x0 and t=theta(1,i0) and c01=1}");

   compose_in1s.push_back("{[0,s0,2,c04,0]->[sigma_out]: sigma_out=sigma_inter2_delta_inv(c04)}");
   compose_in2s.push_back("{[0,s0,1,t,2,i,x]->[0,s0,3,i,x]: t=theta(2,i)} union {[0,s0,1,t,1,i,x]->[0,s0,2,i,x]: t=theta(1,i)} union {[0,s0,1,t,0,i,x]->[0,s0,1,i,x]: t=theta(0,i)} union {[0,s0,0,t,0,i,x]->[0,s0,0,i,x]: 0=t}");
   expected_results.push_back("{[0,s0,1,t,1,i0,x0]->[sigma_out]: x0=0 and t=theta(1,i0) and sigma_out=sigma_inter2_delta_inv(i0)}");

   compose_in1s.push_back("{[0,s0,2,c04,0]->[sigma_out]: sigma_out=sigma_inter1_delta_inv(c04)}");
   compose_in2s.push_back("{[0,s0,1,t,2,i,x]->[0,s0,3,i,x]: t=theta(2,i)} union {[0,s0,1,t,1,i,x]->[0,s0,2,i,x]: t=theta(1,i)} union {[0,s0,1,t,0,i,x]->[0,s0,1,i,x]: t=theta(0,i)} union {[0,s0,0,t,0,i,x]->[0,s0,0,i,x]: 0=t}");
   expected_results.push_back("{[0,s0,1,t,1,i0,x0]->[sigma_out]: sigma_out=sigma_inter1_delta_inv(i0) and x0=0 and t=theta(1,i0)}");

   compose_in1s.push_back("{[0,s0,1,i,x]->[0,s0,1,t,0,i,x]: t=theta(0,i)} union {[0,s0,2,i,x]->[0,s0,1,t,1,i,x]: t=theta(1,i)} union {[0,s0,3,i,x]->[0,s0,1,t,2,i,x]: t=theta(2,i)} union {[0,s0,0,i,x]->[0,s0,0,t,0,i,x]: 0=t}");
   compose_in2s.push_back("{[tstep,i]->[0,tstep,3,i,0]}");
   expected_results.push_back("{[tstep,i]->[0,s0,1,t,2,i0,x0]: tstep=s0 and i=i0 and t=theta(2,i0) and 0=x0}");

   compose_in1s.push_back("{[0,s0,3,c04,0]->[sigma_out]: sigma_out=c04}");
   compose_in2s.push_back("{[0,s0,1,t,2,i,x]->[0,s0,3,i,x]: t=theta(2,i)} union {[0,s0,1,t,1,i,x]->[0,s0,2,i,x]: t=theta(1,i)} union {[0,s0,1,t,0,i,x]->[0,s0,1,i,x]: t=theta(0,i)} union {[0,s0,0,t,0,i,x]->[0,s0,0,i,x]: 0=t}");
   expected_results.push_back("{[0,s0,1,t,2,i0,x0]->[sigma_out]: sigma_out=i0 and 0=x0 and t=theta(2,i0)}");

   compose_in1s.push_back("{[c00,s0,c10,t,c01,i0,x0]->[s0,t,i0]}");
   compose_in2s.push_back("{[sigma_out]->[0,s0,1,t,0,i0,x0]: t=theta(0,i0) and 0=x0 and sigma_out=i0}");
   expected_results.push_back("{[sigma_out]->[s0,t,i0]: i0=sigma_out and t=theta(0,sigma_out)}");

   compose_in1s.push_back("{[c00,s0,c10,t,c01,i0,x0]->[s0,t,i0]: t=t0 and s0=s00 and i0=i00}");
   compose_in2s.push_back("{[sigma_out]->[0,s0,1,t,1,i0,x0]: sigma_out=sigma_inter2_delta_inv(i0) and x0=0 and t=theta(1,i0)}");
   expected_results.push_back("{[sigma_out]->[s0,t,i0]: sigma_out=sigma_inter2_delta_inv(i0) and t=theta(1,i0)}");

   compose_in1s.push_back("{[c00,s0,c10,t,c01,i0,x0]->[s0,t,i0]: t=t0 and s0=s00 and i0=i00}");
   compose_in2s.push_back("{[sigma_out]->[0,s0,1,t,1,i0,x0]: x0=0 and t=theta(1,i0) and sigma_out=sigma_inter1_delta_inv(i0)}");
   expected_results.push_back("{[sigma_out]->[s0,t,i0]: sigma_out=sigma_inter1_delta_inv(i0) and t=theta(1,i0)}");

   compose_in1s.push_back("{[c00,s0,c10,t,c01,i0,x0]->[s0,t,i0]}");
   compose_in2s.push_back("{[sigma_out]->[0,s0,1,t,2,i0,x0]: t=theta(2,i0) and 0=x0 and sigma_out=i0}");
   expected_results.push_back("{[sigma_out]->[s0,t,i0]: t=theta(2,sigma_out) and sigma_out=i0}");

   compose_in1s.push_back("{[c00,s00,c10,t0,c01,i00,x0]->[c00,s00,c10,t0,c01]}");
   compose_in2s.push_back("{[s0,t,i0]->[0,s0,1,t,0,i0,x0]: 0=x0}");
   expected_results.push_back("{[s0,t,i0]->[c001,s001,c101,t01,c011] : c101-1=0 and t-t01=0 and s0-s001=0 and c011=0 and c001=0}");

   compose_in1s.push_back("{[s0,t,i0]->[s0,t]}");
   compose_in2s.push_back("{[0,s0,1,t,0]->[s0,t,i0]}");
   expected_results.push_back("{[0,s0,1,t,0]->[s0,t]}");

   compose_in1s.push_back("{[c00,s00,c10,t,c01,i0,x0]->[c00,s00,c10,t,c01]}");
   compose_in2s.push_back("{[s0]->[0,s0,0,t,0,i0,x0]: 0=i0 and 0=x0 and 0=t}");
   expected_results.push_back("{[s0]->[c001,s001,c101,t1,c011] : t1=0 and s0-s001=0 and c101=0 and c011=0 and c001=0}");

   compose_in1s.push_back("{[c00,s00,c10,t0,c01,i00,x0]->[c00,s00,c10,t0,c01]}");
   compose_in2s.push_back("{[s0,t,i0]->[0,s0,1,t,1,i0,x0]: 0=x0}");
   expected_results.push_back("{[s0,t,i0]->[c001,s001,c101,t01,c011] : c101-1=0 and c011-1=0 and t-t01=0 and s0-s001=0 and c001=0}");

   compose_in1s.push_back("{[s0,t,i0]->[s0,t]}");
   compose_in2s.push_back("{[0,s0,1,t,1]->[s0,t,i0]}");
   expected_results.push_back("{[0,s0,1,t,1]->[s0,t]}");

   compose_in1s.push_back("{[c00,s00,c10,t0,c01,i00,x0]->[c00,s00,c10,t0,c01]}");
   compose_in2s.push_back("{[s0,t,i0]->[0,s0,1,t,2,i0,x0]: 0=x0}");
   expected_results.push_back("{[s0,t,i0]->[c001,s001,c101,t01,c011] : c011-2=0 and c101-1=0 and t-t01=0 and s0-s001=0 and c001=0}");

   compose_in1s.push_back("{[s0,t,i0]->[s0,t]}");
   compose_in2s.push_back("{[s0,1,t,2]->[s0,t,i0]}");
   expected_results.push_back("{[s0,1,t,2]->[s0,t]}");

   //Make sure there are equal numbers of inputs
   ASSERT_EQ(compose_in1s.size(),compose_in2s.size());
   ASSERT_EQ(compose_in2s.size(),expected_results.size());

   for(int i=0; i<compose_in1s.size(); i++) {
      Relation compose_in1(compose_in1s[i]);
      Relation compose_in2(compose_in2s[i]);
      Relation result(compose_in1.Compose(compose_in2));
      Relation expected_result(expected_results[i]);
      ASSERT_EQ(result,expected_result) <<
         compose_in1.get_isl() << endl << ".Compose(" << compose_in2.get_isl() <<
         ") !=" << expected_result.get_isl();
   }
}
